import { message } from "antd";
import { memo, useEffect, useRef, useState } from "react";
import barIcon from "@/assets/barimg.png";
import sucIcon from "@/assets/success.png";
import "./index.less";
interface Props {
  /**
   * @description canvas宽度
   * @default     320
   */
  width?: number;
  /**
   * @description canvas高度
   * @default     160
   */
  height?: number;
  /**
   * @description 滑块图标
   * @default
   */
  barImg?: string;
  /**
   * @description 成功图标
   * @default
   */
  sucImg?: string;
  /**
   * @description 滑块宽度
   * @default     42
   */
  slideWidth?: number;
  /**
   * @description 滑块条高度
   * @default     40
   */
  slideBarHeight?: number;
  /**
   * @description 滑块背景颜色
   * @default     #fff
   */
  handlerBg?: string;
  /**
   * @description 滑块半径
   * @default     9
   */
  slideR?: number;
  /**
   * @description 背景图片
   * @default
   */
  imgSrc?: string;
  /**
   * @description 圆角
   * @default
   */
  radius?: string;
  circle?: boolean;
  text?: string;
  diffWidth?: number;
  progressBarBg?: string;
  successText?: string;
  errorText?: string;
  failTip?: string;
  textColor?: string;

  successTip?: string;
  showTips?: boolean;
  refreshIcon?: string;
  /**
   * @description 成功回调
   */
  onSuccess?: VoidFunction;
  /**
   * @description 失败回调
   */
  onFail?: VoidFunction;
  /**
   * @description 刷新回调
   */

  onRefresh?: VoidFunction;
}
const Slider: React.FC<Props> = memo(
  ({
    width = 320,
    height,
    imgSrc,
    radius = "4px",
    circle = true,
    diffWidth = 15,
    text = "请按住滑块拖动完成拼图",
    successText = "验证成功",
    // errorText = "验证成功",
    refreshIcon = "http://cdn.dooring.cn/dr/icon12.png",
    barImg,
    sucImg,
    onRefresh,
    onSuccess,
    onFail,
    failTip = "验证未通过，拖动滑块将悬浮图像正确合并",
    successTip = "验证通过，超过90%用户",
    showTips = true,
    textColor = "#333",
    handlerBg = "#fff",
    slideBarHeight = 40,
    progressBarBg = "#76c61d",
    slideWidth = 42,
    slideR = 9,
  }) => {
    const canvasRef = useRef<any>(null);
    const blockRef = useRef<any>(null);
    const checkImg = useRef<any>(null);
    const barRef = useRef<any>(null);
    const progressBar = useRef<any>(null);
    const dargSlider = useRef<any>(null);
    const [clipBarx, setClipBarx] = useState<number>(0);
    const [isOk, setIsOk] = useState<boolean>(false);
    const [showErrorTip, setShowErrorTip] = useState<boolean>(false);
    const [curPos] = useState<number>(0);
    const [isPassing, setIsPassing] = useState<boolean>(false);
    const [isMoving, setIsMoving] = useState<boolean>(false);
    const [x, setX] = useState<number>(0);

    const canvasStyle: any = () => {
      return {
        width,
        height,
        overflow: "hidden",
        position: "relative",
      };
    };
    const sliderStyle = () => {
      return {
        width: width + "px",
        height: slideBarHeight + "px",
        lineHeight: height + "px",
        // background: background,
        borderRadius: circle ? Number(slideBarHeight) / 2 + "px" : radius,
      };
    };
    const handlerStyle = () => {
      return {
        left: curPos,
        width: slideBarHeight + 20 + "px",
        height: slideBarHeight + 20 + "px",
        background: handlerBg,
        boxShadow: "0 0 5px #999",
        top: -10,
        borderRadius: circle ? "50%" : radius,
      };
    };
    const draw = (ctx: any, x: any, y: any, operation: any) => {
      const l = Number(slideWidth);
      const r = Number(slideR);
      const PI = Math.PI;

      ctx.beginPath();
      ctx.moveTo(x, y);
      ctx.arc(x + l / 2, y - r + 2, r, 0.72 * PI, 2.26 * PI);
      ctx.lineTo(x + l, y);
      ctx.arc(x + l + r - 2, y + l / 2, r, 1.21 * PI, 2.78 * PI);
      ctx.lineTo(x + l, y + l);
      ctx.lineTo(x, y + l);
      ctx.arc(x + r - 2, y + l / 2, r + 0.4, 2.76 * PI, 1.24 * PI, true);
      ctx.lineTo(x, y);
      ctx.lineWidth = 2;
      ctx.fillStyle = "rgba(255, 255, 255, 0.8)";
      ctx.strokeStyle = "rgba(255, 255, 255, 0.8)";
      ctx.stroke();
      ctx.globalCompositeOperation = "destination-over";
      operation === "fill" ? ctx.fill() : ctx.clip();
    };
    const checkImgLoaded = () => {
      // 生成图片缺失位置
      const barWidth = slideWidth;
      const imgHeight = checkImg.current.height;
      const imgWidth = checkImg.current.width;
      var halfWidth = Math.floor(width / 2);
      var refreshHeigth = 25;
      var tipHeight = 20;
      var x =
        halfWidth +
        Math.ceil(Math.random() * (halfWidth - barWidth - slideR - 5));
      var y =
        refreshHeigth +
        Math.floor(
          Math.random() * (imgHeight - barWidth - refreshHeigth - tipHeight)
        );
      if (!canvasRef) return;

      canvasRef.current?.setAttribute("width", imgWidth);
      canvasRef.current?.setAttribute("height", imgHeight);
      canvasRef.current.style.display = "block";
      var canvasCtx = canvasRef.current?.getContext("2d", {
        willReadFrequently: true,
      });
      draw(canvasCtx, x, y, "fill");
      setClipBarx(x);
      const block = blockRef.current;
      block.setAttribute("width", imgWidth);
      block.setAttribute("height", imgHeight);
      block.style.display = "block";
      const L = barWidth + slideR * 2 + 3;

      var moveCtx = blockRef.current?.getContext("2d", {
        willReadFrequently: true,
      });
      moveCtx.clearRect(0, 0, imgWidth, imgHeight);

      draw(moveCtx, x, y, "clip");
      moveCtx.drawImage(checkImg.current, 0, 0, imgWidth, imgHeight);
      var y = y - slideR * 2 - 1;
      const ImageData = moveCtx.getImageData(x, y, L, L);
      blockRef.current.setAttribute("width", L);
      blockRef.current.setAttribute("height", imgHeight);
      moveCtx.putImageData(ImageData, 0, y);
    };

    // 拖动滑块 开始
    const dragStart = (e: any) => {
      if (!isPassing) {
        setIsMoving(true);

        const x =
          (e.pageX || e.touches[0].pageX) -
          parseInt(barRef.current.style.left.replace("px", ""), 10);

        setX(x);
        setShowErrorTip(false);
      }
    };

    // 拖动滑块中
    const dragMoving = (e: any) => {
      e.preventDefault();
      if (isMoving && !isPassing) {
        const _x = (e.pageX || e.touches[0].pageX) - x;

        if (_x >= 0 && _x <= width - slideBarHeight - 20) {
          barRef.current.style.left = _x + "px";
          progressBar.current.style.width = _x + slideBarHeight + "px";
          blockRef.current.style.left = _x + 3 + "px";
        }
      }
    };

    // 拖动滑块结束

    const dragFinish = (e: any) => {
      if (isMoving && !isPassing) {
        const _x = (e.pageX || e.changedTouches[0].pageX) - x;

        if (Math.abs(_x - clipBarx) > diffWidth) {
          setIsOk(true);
          setTimeout(() => {
            progressBar.current.style.width = 0;
            barRef.current.style.left = 0;
            blockRef.current.style.left = 0;
            setIsOk(false);
          }, 500);
          message.error("验证失败");
          setShowErrorTip(true);
          typeof onFail === "function" && onFail();
        } else {
          message.success("验证成功");
          setIsPassing(true);
          setTimeout(() => {
            canvasRef.current.style.display = "none";
            blockRef.current.style.display = "none";
          }, 200);
          typeof onSuccess === "function" && onSuccess();
        }
        setIsMoving(false);
      }
    };
    const handleRefresh = () => {
      checkImgLoaded();
      typeof onRefresh === "function" && onRefresh();
    };

    useEffect(() => {
      dargSlider.current?.style.setProperty("--textColor", textColor);
      dargSlider.current?.style.setProperty(
        "--width",
        Math.floor(Number(width) / 2) + "px"
      );
      dargSlider.current?.style.setProperty(
        "--pwidth",
        -Math.floor(Number(width) / 2) + "px"
      );
    }, []);
    return (
      <div className="slider_wrap" style={{ width: width, margin: "auto" }}>
        <div style={canvasStyle()}>
          <img
            ref={checkImg}
            onLoad={checkImgLoaded}
            crossOrigin="anonymous"
            src={imgSrc}
            style={{ width: "100%" }}
            alt=""
          />
          <canvas className="main_canvas" ref={canvasRef}></canvas>
          <canvas
            className={["move_canvas", isOk ? "goFirst" : null].join(" ")}
            ref={blockRef}
          ></canvas>
          {isPassing ? null : (
            <div
              className="refreshIcon"
              onClick={handleRefresh}
              style={{ backgroundImage: `url(${refreshIcon})` }}
            ></div>
          )}
          {showTips && !isPassing && showErrorTip ? (
            <div className="tips danger">{failTip}</div>
          ) : null}
          {showTips && isPassing ? (
            <div className="tips success">{successTip}</div>
          ) : null}
        </div>
        <div
          style={{
            position: "relative",
            width: width,
          }}
          onMouseMove={dragMoving}
          onMouseUp={dragFinish}
          onMouseLeave={dragFinish}
          onTouchMove={dragMoving}
          onTouchEnd={dragFinish}
        >
          <div
            ref={dargSlider}
            style={sliderStyle()}
            className="slider_container"
          >
            <div className="wrap">
              <div className="text">{isPassing ? "" : text}</div>
            </div>
            <div
              style={{
                background: progressBarBg,
                height: slideBarHeight,
                borderRadius: circle ? slideBarHeight / 2 : radius,
              }}
              ref={progressBar}
              className={["progress_bar", isOk ? "goFirst2" : null].join(" ")}
            >
              {isPassing ? successText : ""}
            </div>
          </div>
          <div
            style={handlerStyle()}
            onMouseDown={dragStart}
            onTouchStart={dragStart}
            className={["slider_bar", isOk ? "goFirst" : null].join(" ")}
            ref={barRef}
          >
            <img
              src={isPassing ? sucImg ?? sucIcon : barImg ?? barIcon}
              width="30px"
              height="30px"
              alt=""
            />
          </div>
        </div>
      </div>
    );
  }
);

export default Slider;
